package com.witmore.neutron.ai.web.wechat.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jk.mp.wx.response.WechatAuthAccessToken;
import com.witmore.neutron.ai.web.wechat.service.WechatTokenCacheService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.concurrent.TimeUnit;

/**
 * 微信Token缓存服务实现类
 * Author: 豆子高
 * Date: 2025/01/21
 */
@Slf4j
@Service
public class WechatTokenCacheServiceImpl implements WechatTokenCacheService {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    private final ObjectMapper objectMapper = new ObjectMapper();

    private static final String WECHAT_TOKEN_PREFIX = "wechat:auth_login:token:";
    private static final String WECHAT_TOKEN_EXPIRE_PREFIX = "wechat:auth_login:token:expire:";

    // 提前5分钟刷新token
    private static final int REFRESH_BEFORE_EXPIRE_MINUTES = 5;

    @Override
    public void cacheAccessToken(String openid, WechatAuthAccessToken accessToken) {
        if (!StringUtils.hasText(openid) || accessToken == null) {
            log.warn("openid或accessToken为空，无法缓存");
            return;
        }

        try {
            String key = WECHAT_TOKEN_PREFIX + openid;
            String expireKey = WECHAT_TOKEN_EXPIRE_PREFIX + openid;

            // 序列化token对象
            String tokenJson = objectMapper.writeValueAsString(accessToken);

            // 缓存token，设置过期时间（微信token有效期通常为2小时，这里设置为比实际时间少一点，确保安全）
            int expireTime = accessToken.getExpiresIn() != null ? accessToken.getExpiresIn() - 60 : 7140; // 默认119分钟
            redisTemplate.opsForValue().set(key, tokenJson, expireTime, TimeUnit.SECONDS);

            // 单独存储过期时间戳，用于判断是否即将过期
            long expireTimestamp = System.currentTimeMillis() + (expireTime * 1000L);
            redisTemplate.opsForValue().set(expireKey, String.valueOf(expireTimestamp), expireTime, TimeUnit.SECONDS);

            log.info("成功缓存微信token: openid={}, 过期时间={}秒", openid, expireTime);

        } catch (JsonProcessingException e) {
            log.error("序列化微信token失败: openid={}", openid, e);
        } catch (Exception e) {
            log.error("缓存微信token失败: openid={}", openid, e);
        }
    }

    @Override
    public WechatAuthAccessToken getCachedAccessToken(String openid) {
        if (!StringUtils.hasText(openid)) {
            return null;
        }

        try {
            String key = WECHAT_TOKEN_PREFIX + openid;
            String tokenJson = redisTemplate.opsForValue().get(key);

            if (!StringUtils.hasText(tokenJson)) {
                log.debug("缓存中未找到微信token: openid={}", openid);
                return null;
            }

            WechatAuthAccessToken accessToken = JSONObject.parseObject(tokenJson, WechatAuthAccessToken.class);
            log.debug("从缓存获取微信token成功: openid={}", openid);
            return accessToken;

        } catch (Exception e) {
            log.error("从缓存获取微信token失败: openid={}", openid, e);
            return null;
        }
    }

    @Override
    public void removeCachedAccessToken(String openid) {
        if (!StringUtils.hasText(openid)) {
            return;
        }

        try {
            String key = WECHAT_TOKEN_PREFIX + openid;
            String expireKey = WECHAT_TOKEN_EXPIRE_PREFIX + openid;

            redisTemplate.delete(key);
            redisTemplate.delete(expireKey);

            log.info("删除微信token缓存: openid={}", openid);

        } catch (Exception e) {
            log.error("删除微信token缓存失败: openid={}", openid, e);
        }
    }

    @Override
    public boolean isTokenExpiringSoon(String openid) {
        if (!StringUtils.hasText(openid)) {
            return false;
        }

        try {
            String expireKey = WECHAT_TOKEN_EXPIRE_PREFIX + openid;
            String expireTimestampStr = redisTemplate.opsForValue().get(expireKey);

            if (!StringUtils.hasText(expireTimestampStr)) {
                return false; // 没有缓存的过期时间，认为不存在
            }

            long expireTimestamp = Long.parseLong(expireTimestampStr);
            long currentTime = System.currentTimeMillis();
            long timeToExpire = expireTimestamp - currentTime;

            // 如果剩余时间少于5分钟，认为即将过期
            boolean expiringSoon = timeToExpire < (REFRESH_BEFORE_EXPIRE_MINUTES * 60 * 1000L);

            if (expiringSoon) {
                log.info("微信token即将过期: openid={}, 剩余时间={}秒", openid, timeToExpire / 1000);
            }

            return expiringSoon;

        } catch (NumberFormatException e) {
            log.error("解析过期时间戳失败: openid={}", openid, e);
            return false;
        } catch (Exception e) {
            log.error("检查token过期时间失败: openid={}", openid, e);
            return false;
        }
    }
}
